package com.qipay.db.domains;

import com.qi.protocol.constants.CertificateProcess;
import com.qi.protocol.constants.UserType;
import com.qi.qipay.commons.utils.MD5Util;
import com.qi.qipay.commons.utils.StringUtil;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.bson.types.ObjectId;

import javax.persistence.*;
import javax.validation.constraints.Size;
import java.sql.Timestamp;

@Entity
@Table(name = "user")
public class User {

    private static final int ADVANCE_TIME = 10 * 60;

    @Id
    @Column(name = "id", length = 24, unique = true, updatable = false)
    @Getter
    @Setter(AccessLevel.PROTECTED)
    private String id = new ObjectId().toString();

    @Getter
    @Setter
    @Enumerated(EnumType.STRING)
    @Column(name = "type", length = 16, nullable = false)
    private UserType type;

    @Getter
    @Setter
    @Column(name = "username", length = 16, unique = true)
    @Size(min = 11, max = 14, message = "用户名必须为合法手机号码")
    private String username;

    @Getter
    @Column(name = "password", length = 32)
    @Size(min = 6, max = 20, message = "密码必须大于6位且小于20位")
    private String password;

    @Getter
    @Setter
    @Column(name = "name", length = 16)
    private String name;

    @Getter
    @Setter
    @Column(name = "idNo", length = 18)
    @Size(min = 18, max = 18, message = "身份证号码不正确！")
    private String idNo;

    @Getter
    @Setter
    @JoinColumn(name = "idCardPhoto", referencedColumnName = "id", unique = true)
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Document idCardPhoto;

    @Getter
    @Setter
    @JoinColumn(name = "idCardBackPhoto", referencedColumnName = "id", unique = true)
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Document idCardBackPhoto;

    @Getter
    @Setter
    @Enumerated(EnumType.STRING)
    @Column(name = "certificateProcess", length = 16)
    private CertificateProcess certificateProcess = CertificateProcess.NEW;

    @Getter
    @Setter
    @Column(name = "salt", length = 8, nullable = false)
    private String salt = StringUtil.randomString(8);

    @Getter
    @Setter(AccessLevel.PROTECTED)
    @Column(name = "token", length = 32, unique = true)
    private String token;

    @Getter
    @Setter(AccessLevel.PROTECTED)
    @Column(name = "tokenExpiration")
    private Timestamp tokenExpiration;

    @Getter
    @Setter
    @Column(name = "updated", nullable = false)
    private Timestamp updated;

    @Getter
    @Setter(AccessLevel.PROTECTED)
    @Column(name = "created", updatable = false)
    private Timestamp created = new Timestamp(System.currentTimeMillis());

    public User() {
    }

    public User(UserType type,
                @Size(min = 11, max = 14, message = "用户名必须为合法手机号码") String username,
                @Size(min = 6, max = 20, message = "密码必须大于6位且小于20位") String password) {
        this.type = type;
        this.username = username;
        this.setPassWord(password);
    }

    public User(UserType type, @Size(min = 11, max = 14, message = "用户名必须为合法手机号码") String username) {
        this.type = type;
        this.username = username;
    }

    public void setPassWord(@Size(min = 6, max = 20, message = "密码必须大于6位且小于20位") String password) {
        this.password = MD5Util.md5WithSalt(password, this.salt);
    }

    public boolean certificated() {
        return this.certificateProcess == CertificateProcess.FINISHED;
    }

    public User certificate(String name, String idNo, Document idCardPhoto, Document idCardBackPhoto) {
        this.name = name;
        this.idNo = idNo;
        this.idCardPhoto = idCardPhoto;
        this.idCardBackPhoto = idCardBackPhoto;
        this.certificateProcess = CertificateProcess.WAIT;
        return this;
    }

    public User finishCertificate() {
        this.certificateProcess = CertificateProcess.FINISHED;
        return this;
    }

    public User genToken(long expireInterval) {
        if (this.tokenExpiration == null || this.tokenExpiration.getTime() < System.currentTimeMillis() - ADVANCE_TIME) {
            this.token = StringUtil.randomUUID();
            this.tokenExpiration = new Timestamp(System.currentTimeMillis() + expireInterval);
        }
        return this;
    }

    public User refreshToken(long expireInterval) {
        this.token = StringUtil.randomUUID();
        this.tokenExpiration = new Timestamp(System.currentTimeMillis() + expireInterval);
        return this;
    }

    public User destoryToken() {
        this.token = null;
        this.tokenExpiration = null;
        return this;
    }

    public boolean verifyPassword(String password) {
        return this.password.equals(MD5Util.md5WithSalt(password, this.salt));
    }

    public boolean verifyToken(String token) {
        return token != null && token.equals(this.token) && this.tokenExpiration.getTime() >= System.currentTimeMillis();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        return id.equals(user.id);
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }
}
